/* eslint global-require: off, no-console: off, promise/always-return: off */

/**
 * This module executes inside of electron's main process. You can start
 * electron renderer process from here and communicate with the other processes
 * through IPC.
 *
 * When running `npm run build` or `npm run build:main`, this file is compiled to
 * `./src/main.js` using webpack. This gives us some performance wins.
 */
import path from 'path';
import { app, BrowserWindow, shell, ipcMain, BrowserView, dialog } from 'electron';
import { autoUpdater } from 'electron-updater';
import log from 'electron-log';
import MenuBuilder from './menu';
import { resolveHtmlPath } from './util';
import { downlodAndSaveM3U8, downlodAndSaveTS } from '../libs/downlod';
import server from '../libs/server'
import console from 'console';
import Config from '../config/config';
import { TaskStatus } from '../renderer/constants/Consts';
import { IDownloadDBTask } from 'model/DB';

const fs = require('fs-extra')

const Store = require('electron-store')

// process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'

// export default class AppUpdater {
//   constructor() {
//     log.transports.file.level = 'info';
//     autoUpdater.logger = log;
//     autoUpdater.checkForUpdatesAndNotify();
//   }
// }

log.info('app main render')


let mainWindow: BrowserWindow | null = null;

let loginWindow: BrowserView | null = null


// 本地缓存
Store.initRenderer()
const store = new Store()
// store.clear()


let token: string = ''

// ipcMain.on('ipc-example', async (event, arg) => {
//   const msgTemplate = (pingPong: string) => `IPC test: ${pingPong}`;
//   console.log(msgTemplate(arg));
//   event.reply('ipc-example', msgTemplate('pong'));
// });

if (process.env.NODE_ENV === 'production') {
  const sourceMapSupport = require('source-map-support');
  sourceMapSupport.install();
}

const isDevelopment =
  process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true';

if (isDevelopment) {
  require('electron-debug')();
}

// const installExtensions = async () => {
//   const installer = require('electron-devtools-installer');
//   const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
//   const extensions = ['REACT_DEVELOPER_TOOLS'];

//   return installer
//     .default(
//       extensions.map((name) => installer[name]),
//       forceDownload
//     )
//     .catch(console.log);
// };

const createWindow = async () => {
  if (isDevelopment) {
    // await installExtensions();
  }

  const RESOURCES_PATH = app.isPackaged
    ? path.join(process.resourcesPath, 'assets')
    : path.join(__dirname, '../../assets');

  const getAssetPath = (...paths: string[]): string => {
    return path.join(RESOURCES_PATH, ...paths);
  };

  mainWindow = new BrowserWindow({
    show: false,
    width: 1060,
    height: 600,
    minWidth: 1060,
    minHeight: 600,
    icon: getAssetPath('icon.png'),
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      nodeIntegration: true,
      nodeIntegrationInWorker: true,
      // contextIsolation: false,
    },
  });
  mainWindow.setAspectRatio(16/9, {width: 260, height: 150})

  if(isDevelopment) {
    mainWindow.webContents.openDevTools({mode: 'undocked'})
  }
  // mainWindow.webContents.openDevTools({mode: 'undocked'})

  mainWindow.loadURL(resolveHtmlPath('index.html'));

  mainWindow.on('ready-to-show', () => {
    if (!mainWindow) {
      throw new Error('"mainWindow" is not defined');
    }

    if (process.env.START_MINIMIZED) {
      mainWindow.minimize();
    } else {
      mainWindow.show();
    }
  });

  mainWindow.on('closed', () => {
    mainWindow = null;
  });

  const menuBuilder = new MenuBuilder(mainWindow);
  // menuBuilder.buildMenu();
  menuBuilder.removeMenu()

  // Open urls in the user's browser
  mainWindow.webContents.setWindowOpenHandler((edata) => {
    shell.openExternal(edata.url);
    return { action: 'deny' };
  });

  // Remove this if your app does not use auto updates
  // eslint-disable-next-line
  // new AppUpdater();

  loginWindow = new BrowserView({webPreferences: {
    // preload: path.join(__dirname, './login-preload.js'),
    // devTools: true
  }})
  // mainWindow.setBrowserView(loginWindow)
  mainWindow.addBrowserView(loginWindow)
  loginWindow.setBounds({ x: 0, y: 0, width: 1060, height: 600 })
  loginWindow.setAutoResize({width: true, height: true})


  loginWindow.webContents.on('did-finish-load', () => {
    if(isDevelopment && process.platform !== 'darwin') {
      loginWindow!.webContents.insertCSS('html { width: 100%; height: 100%; overflow: hidden; transform: scale(1.5) translatey(20%); } body {width: 100%; height: 100%;} ')
    } else {
      loginWindow!.webContents.insertCSS('html { width: 100%; height: 100%; overflow: hidden;  } body {width: 100%; height: 100%;} ')
    }
  })

  // loginWindow.webContents.openDevTools({mode: 'undocked'})


  // 拦截登陆窗口请求
  const loginRequestFilter = {
    urls: [] //['*://iaaa.pku.edu.cn']
  }
  const ses = loginWindow!.webContents.session
  ses.clearCache()
  let infoToken = ''
  loginWindow.webContents.session.webRequest.onCompleted(loginRequestFilter, async (details) => {
    // console.log('details.url =', details.url, details.statusCode)

    // 取 info token 用于获取用户信息
    const infoUrl = Config.cookieUrl + '?token='
    if(details.url.indexOf(infoUrl) === 0){
      infoToken = details.url.substring(infoUrl.length)
      // console.log('infotoken =', details.url)
    }

    // 拦截登陆信息接口
    const cookieUrl = Config.cookieUrl+'iaaa/'
    if(details.url === cookieUrl && details.statusCode === 403) {
      const ses = loginWindow!.webContents.session

      const cookies = await ses.cookies.get({url: Config.cookieUrl})
      // console.log('cookie ==', cookies)
      // 通知渲染进程，获取到cookie
      const cookie = cookies.find(item => item.name === '_token')

      // 登陆成功
      if(cookie) {
        // 关闭登陆页窗口
        mainWindow?.removeBrowserView(loginWindow!)

        token = cookie.value

        mainWindow?.webContents.send('user-info', {
          name: '用户',
          token,
          infoToken,
          account: '',
          id: Number.NaN,
          tenant_id: Number.NaN
        })

        // 清除缓存 下次打开页面需要重新登陆
        // await ses.clearCache()
        const resp = await ses.cookies.remove(Config.cookieUrl, '_token')
        // console.log('cookie remove ==', resp)

        log.info(`login success `)

        // 设置主窗口 cookie
        // mainWindow?.webContents.session.cookies.set({
        //   url: 'https://livingapihqy.pku.edu.cn',  //'http://localhost:1212',
        //   name: 'token',
        //   value: token,
        //   domain: '.pku.edu.cn'
        // })
        // .then(() => {

        // })
        // .catch(err => {
        //   console.log('set cookie =', err)
        // })
      }
    }
  })

  // 阻止登录页点击跳转
  const openRequestFilter = {
    urls: ['http://www.pku.edu.cn/', 'http://cc.pku.edu.cn/']
  }
  loginWindow.webContents.session.webRequest.onBeforeRequest(openRequestFilter, (details, callback) => {
    // console.log('details =', details.url)
    callback({cancel: true})

    loginWindow!.webContents.loadURL(Config.loginUrl)

  })


  // 设置静态服务的托管地址
  const paths = store.get('save-path-list')
  // console.log('static paths: ', paths)
  if(paths) {
    paths.forEach((item: any) => {
      server.setStaticPath(item)
    });
  }


  // 拦截请求，并设置cookie，用于播放m3u8解密
  const filter = {
    urls: [
      '*://livingapihqy.pku.edu.cn/*',
      '*://livingroomhqy.pku.edu.cn/*',
      '*://resourcese.pku.edu.cn/*',
      '*://vod.pku.edu.cn/*',
      '*://vodse.pku.edu.cn/*',
      '*://playse.pku.edu.cn/*',
    ]
  }
  mainWindow.webContents.session.webRequest.onBeforeSendHeaders(filter, (details, callback) => {
    // details.requestHeaders['User-Agent'] = 'MyAgent'
    // console.log('details =', details.url)
    details.requestHeaders['Cookie'] = `_token=${token}`
    callback({cancel: false, requestHeaders: details.requestHeaders})
  })

  // 发送程序是否关闭
  mainWindow.on('close', (event) => {
    // console.log('main close')
    event.preventDefault()

    // mainWindow?.webContents.send
    mainWindow?.webContents.send('will-close')
  })


};


// ------------- 写入注册表 --------

if (!app.isDefaultProtocolClient('pkuofflineapp')) {
  const result = app.setAsDefaultProtocolClient('pkuofflineapp')
  log.info('app set protocol result :', result)
}

// ---------------- 单例模式 ---------------------------
// app.on("first-instance-ack", (event, additionalData) => {
//   // 打印出从第一实例接收的 ack
//   // 注意事件处理程序调用，必须在 requestSingleInstanceLock 调用之前。
//   // 预计输出： '{"myAckKey":"myAckValue"}'
//   console.log(JSON.stringify(additionalData))
// })

// const additionalData = { myKey: 'myValue' }
// const gotTheLock = app.requestSingleInstanceLock(additionalData)
const gotTheLock = app.requestSingleInstanceLock()

if (!gotTheLock) {
  app.quit()
} else {
  // win 系统
  app.on('second-instance', (event, commandLine, workingDirectory, additionalData) => {
    // 如果我们要回传数据，就必须调用 preventDefault 。
    event.preventDefault()
    // 打印出从第二实例接收的数据。
    // 预计输出：'{"myKey":"myValue"}'
    // console.log(JSON.stringify(additionalData))

    // 尝试使用第二实例，我们应该使我们的窗口获得焦点。
    if (mainWindow) {
      if (mainWindow.isMinimized()) mainWindow.restore()
      mainWindow.focus()
    }
    // const ackData = { myAckKey: 'myAckValue' }
    // ackCallback(ackData)
  })

  // mac 系统
  app.on('open-url', (event, url) => {
    // const isProtocol = AGREEMENT_REGEXP.test(url)
    // if (isProtocol) {
    //   console.log('获取协议链接, 根据参数做各种事情')
    //   dialog.showMessageBox({
    //     type: 'info',
    //     message: 'Mac protocol 自定义协议打开',
    //     detail: `自定义协议链接:${url}`,
    //   })
    // }
    event.preventDefault()
    if (mainWindow) {
      if (mainWindow.isMinimized()) mainWindow.restore()
      mainWindow.focus()
    }
  })

  // app.on('second-instance', (event, commandLine, workingDirectory) => {
  //   log.info('second-instance-start');
  //   // 当运行第二个实例时,将会聚焦到myWindow这个窗口
  //   if (mainWindow) {
  //     if (mainWindow.isMinimized()) mainWindow.restore();
  //     mainWindow.focus();
  //   } else {
  //     if (!isWindows) {
  //       if (app.isReady()) createWindow();
  //     }
  //   }
  //   if (isWindows) {
  //     log.info('second-instace');
  //     let commands = commandLine.slice();
  //     // commandLine 是一个数组， 其中最后一个数组元素为我们唤醒的链接
  //     activeUrl = decodeURI(commands.pop());
  //     // mainWindow.loadURL();
  //     whenUrlActive();
  //   }
  // });

  // 创建 myWindow，加载应用的其它功能，等等...
  // app.whenReady().then(() => {
  //   myWindow = createWindow()
  // })
  app.whenReady()
    .then(() => {
      // 启动本地服务
      const localCfg = store.get('local-config')
      // console.log('localCfg =', localCfg)
      if(localCfg && localCfg.port) {
        Config.serverPort = localCfg.port
      }
      server.startServer()

      // 启动窗口
      createWindow();
      app.on('activate', () => {
        // On macOS it's common to re-create a window in the app when the
        // dock icon is clicked and there are no other windows open.
        if (mainWindow === null) createWindow();
      });
    })
    .catch(console.log);
}
// ---------------- 单例模式 ---------------------------

/**
 * Add event listeners...
 */

app.on('window-all-closed', () => {
  // Respect the OSX convention of having the application in memory even
  // after all windows have been closed
  if (process.platform !== 'darwin') {
    app.quit();
  }
});



// 响应渲染进程决定的是否关闭程序世界
ipcMain.on('exit-app', (event, art) => {
  app.exit();

})


// 打开登录页
ipcMain.on('open-login', (event, arg) => {
  console.log('open-login')
  // 移除缓存信息
  store.set('user-info', {
    name: '',
    token: '',
    infoToken: '',
    account: '',
    id: Number.NaN,
    tenant_id: Number.NaN
  })
  // console.log('loginWindow/mainWindow ',mainWindow, loginWindow)
  if(loginWindow && mainWindow) {
    // mainWindow.setBrowserView(loginWindow)
    console.log('add login')
    mainWindow.addBrowserView(loginWindow)
    // // loginWindow.webContents.loadURL('https://passport.pku.edu.cn/auth/login?redirect=http://resource.pku.edu.cn')
    // // loginWindow.webContents.loadURL('https://loginyjhqy.pku.edu.cn/?forward=https%3A%2F%2Fonlineroomhqy.pku.edu.cn%2F&tenant_code=1')
    // // console.log('loginUrl =', Config.loginUrl)
    loginWindow.webContents.loadURL(Config.loginUrl)
  }
})

// 获取本地缓存
ipcMain.handle('get-store-value', (event, key) => {
  const result = store.get(key)
  if(key === 'user-info') {
    // 获取本地缓存信息时
    token = result ? result.token : ''

    if (result) {
      console.log('remove login')
      mainWindow?.removeBrowserView(loginWindow!)
    }

  } else if(key === 'save-path') {
    // 获取存储目录时，需要先判断该目录是否已存在， 如果该目录不存在，提示用户创建
    if(!fs.existsSync(result)) {
      store.set('save-path', '')
      return ''
    }
  }

  return result
})
ipcMain.on('set-store-value', (event, {key, data}) => {
  store.set(key, data)
})
// 获取主进程配置
ipcMain.handle('get-local-config', (event, key) => {
  return Config
})


// 设置保存路径
ipcMain.handle('set-save-path', async (event, path) => {

  const oldPath = path ? path : app.getPath('downloads')

  const { canceled, filePaths } = await dialog.showOpenDialog(mainWindow!, {
    title: '选择保存位置',
    properties: ['openDirectory', 'createDirectory'],
    defaultPath: oldPath
  })

  const newPath = !canceled ? filePaths[0] : oldPath

  if(canceled === false) {
    // 保持当前位置到本地
    store.set('save-path', newPath)

    // 设置静态服务的托管地址
    server.setStaticPath(newPath)
    log.info('set save path: ', newPath)

    // 保存多个 savepath 用于下次静态服务的托管地址
    const paths = store.get('save-path-list')

    if(paths){
      paths.push(newPath)

      store.set('save-path-list', paths)
    } else {
      store.set('save-path-list', [newPath])
    }


  }

  return newPath

})

// 下载m3u8文件
ipcMain.handle('start-download-m3u8', async (event, {url, filePath, fileName}) => {
  // console.log('url ==', url)
  // const result = await
  return downlodAndSaveM3U8(url, filePath, fileName)
})

// 下载 ts 文件
ipcMain.on('start-download-ts', async (event, {url, filePath, taskId, name}) => {
  // 需要返回哪个ts文件下载完成
  // log.info('start-download-ts: ', url)
  const result = await downlodAndSaveTS(url, filePath)
  event.reply('download-ts-reply', {
    result,
    taskId,
    name,
    url,
    filePath
  })
})

ipcMain.on('delete-directory', async (event, filePath) => {
  fs.remove(filePath, (err: any) => {
    if(err) {
      log.info('删除目录失败: ', filePath, err)
    }
  })
})

// 获取目录
ipcMain.handle('get-directory', async (event, path) => {


  const { canceled, filePaths } = await dialog.showOpenDialog(mainWindow!, {
    title: '选择保存位置',
    properties: ['openDirectory', 'createDirectory'],

    // defaultPath: oldPath
  })

  if(!canceled) {
    return filePaths[0]
  } else {
    return ''
  }

})

// 导入本地课程
ipcMain.handle('import-course', async (event, dirPath) => {

  const result: IDownloadDBTask[] = []

  // 读取当前目录下面的所有子目录，并且读取每个子目录下面的 task.json 文件，
  const list = fs.readdirSync(dirPath)

  list.forEach((item: string) => {
    const taskPath = path.resolve(dirPath, item)

    try {
      const stat = fs.statSync(taskPath);
      if(stat.isDirectory()) {
        // 读取目录下面的 文件
        const file = path.resolve(taskPath, "task.json")
        // console.log('file ==', file)
        const task: IDownloadDBTask = JSON.parse(fs.readFileSync(file))
        // 只读取已下载完成的课程
        if(task.status === TaskStatus.Done) {
          result.push(task)
          console.log('import course parse task: ', task)
        }
      }

    } catch (error: any) {
      log.error('import course parse task error: ', error.toString())
    }


  });

  return result

})

// 写入课程task.json 文件
ipcMain.on('write-task', async (event, task) => {

  const taskpath = path.resolve(path.dirname(task.path), 'task.json')

  try {
    const taskString = JSON.stringify(task)
    const writeResult = fs.writeFileSync(taskpath, taskString)
    log.info('write task json: ', taskpath, taskString)
  } catch (error) {
    log.error('write task json error: ', error)
  }

})

// 设置本地服务，课程静态目录
ipcMain.on('set-server-static-path', (event, staticPath) => {
  // 设置静态服务的托管地址

  // 保存多个 staticPath 用于下次静态服务的托管地址
  const paths = store.get('save-path-list')
  if(paths){
    if(!paths.includes(staticPath)) {
      paths.push(staticPath)

      store.set('save-path-list', paths)

      server.setStaticPath(staticPath)
      log.info('set static path: ', staticPath)
    }

  } else {
    store.set('save-path-list', [staticPath])

    server.setStaticPath(staticPath)
    log.info('set static path: ', staticPath)
  }
})
